package handler

import (
	"context"
	"errors"
	"github.com/golang/protobuf/ptypes/empty"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"pm_back_server/project-server/global"
	"pm_back_server/project-server/model"
	"pm_back_server/project-server/proto"
	"pm_back_server/project-server/utils"
	"time"
)

func HandleIterationModelToResponse(iterationModel *model.Iteration) *proto.IterationResponseInfo {
	return &proto.IterationResponseInfo{
		Id:        uint64(iterationModel.ID),
		Name:      iterationModel.Name,
		Desc:      iterationModel.Desc,
		Cover:     iterationModel.Cover,
		StartTime: uint64(iterationModel.StartTime.Unix()),
		EndTime:   uint64(iterationModel.EndTime.Unix()),
		ProjectId: iterationModel.ProjectId,
	}
}

// CreateIteration /* 创建迭代
func (p *ProjectServer) CreateIteration(ctx context.Context, req *proto.CreateIterationInfo) (*proto.IterationResponseInfo, error) {
	// 判断项目是否存在
	var project model.Project
	result := global.DB.First(&project, req.ProjectId)
	if result.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, ProjectNotFound)
	}
	// 获取团队ID GroupId
	groupId := p.GetGroupIdByProjectId(req.ProjectId)
	if groupId == 0 {
		zap.S().Errorw("[CreateIteration] 查询 [项目ID] 失败")
		return nil, status.Errorf(codes.NotFound, GroupNotFoundStr)
	}
	// 检验是否具有权限
	if !CheckAuthority(groupId, req.LeaderId) {
		zap.S().Errorw("[CreateIteration] 校验 [权限] 失败")
		return nil, status.Errorf(codes.Unavailable, Unavailable)
	}
	// 创建迭代
	startTime := time.Unix(int64(req.StartTime), 0)
	endTime := time.Unix(int64(req.EndTime), 0)
	iteration := model.Iteration{
		Name:      req.Name,
		Desc:      req.Desc,
		Cover:     req.Cover,
		StartTime: &startTime,
		EndTime:   &endTime,
		ProjectId: req.ProjectId,
		GroupId:   groupId,
	}
	result = global.DB.Model(&model.Iteration{}).Create(&iteration)
	if result.Error != nil {
		zap.S().Errorw("[CreateIteration] 创建 [迭代] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	return HandleIterationModelToResponse(&iteration), nil
}

// GetIterationById /* 通过迭代ID查找迭代
func (p *ProjectServer) GetIterationById(ctx context.Context, req *proto.IterationIdInfo) (*proto.IterationResponseInfo, error) {
	var iteration model.Iteration
	result := global.DB.First(&iteration, req.Id)

	if result.RowsAffected == 0 {
		zap.S().Errorw("[GetIterationById] 查询 [迭代] 失败")
		return nil, status.Errorf(codes.NotFound, IterationNotFoundStr)
	}

	return HandleIterationModelToResponse(&iteration), nil
}

// GetIterationListByProjectId /* 通过项目ID查询迭代列表
func (p *ProjectServer) GetIterationListByProjectId(ctx context.Context, req *proto.ProjectIdInfo) (*proto.IterationListResponseInfo, error) {
	var project model.Project
	result := global.DB.First(&project, req.Id)
	if result.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, ProjectNotFound)
	}

	var iterations []model.Iteration
	result = global.DB.Model(&model.Iteration{}).Where("project_id = ?", req.Id).Find(&iterations)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	rsp := &proto.IterationListResponseInfo{}
	for _, iteration := range iterations {
		rsp.IterationList = append(rsp.IterationList, HandleIterationModelToResponse(&iteration))
	}
	return rsp, nil
}

// UpdateIteration /* 更新迭代
func (p *ProjectServer) UpdateIteration(ctx context.Context, req *proto.UpdateIterationInfo) (*empty.Empty, error) {
	// 判断是否具有权限
	if !CheckAuthority(req.GroupId, req.UserId) {
		zap.S().Errorw("[UpdateIteration] 更新 [迭代] 用户不具有权限")
		return nil, status.Errorf(codes.Unavailable, Unavailable)
	}
	// 判断迭代是否存在
	var iteration model.Iteration
	result := global.DB.First(&iteration, req.Id)
	if result.RowsAffected == 0 {
		zap.S().Errorw("[UpdateIteration] 更新 [迭代] 目标迭代不存在")
		return nil, status.Errorf(codes.NotFound, IterationNotFoundStr)
	}
	// 更新迭代
	iteration.Name = req.Name
	iteration.Desc = req.Desc
	iteration.Cover = req.Cover
	startTime := time.Unix(int64(req.StartTime), 0)
	endTime := time.Unix(int64(req.EndTime), 0)
	iteration.StartTime = &startTime
	iteration.EndTime = &endTime
	result = global.DB.Save(&iteration)
	if result.Error != nil {
		zap.S().Errorw("[UpdateIteration] 更新 [迭代] 目标迭代更新失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	return &empty.Empty{}, nil
}

// DeleteIteration /* 删除迭代
func (p *ProjectServer) DeleteIteration(ctx context.Context, req *proto.DeleteIterationInfo) (*empty.Empty, error) {
	errorLogger := utils.NewErrorLogger("DeleteIteration")
	// 校验是否具有权限
	if !CheckAuthority(req.GroupId, req.UserId) {
		errorLogger("校验", "权限", "用户不具备删除权限")
		return nil, status.Errorf(codes.Unavailable, Unavailable)
	}
	// 判断是否存在迭代
	if !CheckIterationExist(req.Id) {
		errorLogger("查询", "迭代", "目标迭代不存在")
		return nil, status.Errorf(codes.NotFound, IterationNotFoundStr)
	}
	// 删除迭代所属的任务
	if err := p.DeleteTaskByIterationId(&proto.IterationIdInfo{Id: req.Id}); err != nil {
		errorLogger("删除", "任务", "删除迭代所需任务失败")
		return nil, status.Errorf(codes.Internal, err.Error())
	}
	// 删除迭代
	var iteration model.Iteration
	result := global.DB.Model(&model.Iteration{}).Delete(&iteration, req.Id)
	if result.Error != nil {
		errorLogger("删除", "迭代", "删除目标迭代失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	return &empty.Empty{}, nil
}

// DeleteIterationByGroupId /* 通过团队ID删除迭代
func (p *ProjectServer) DeleteIterationByGroupId(req *proto.GroupIdInfo) error {
	if !CheckGroupExist(req.Id) {
		zap.S().Errorw("[DeleteIterationById] 查询 [团队] 失败")
		return errors.New("删除迭代失败")
	}

	var iterations []model.Iteration
	result := global.DB.Model(&model.Iteration{}).Where("group_id = ?", req.Id).Delete(&iterations)
	if result.Error != nil {
		zap.S().Errorw("[DeleteIterationById] 删除 [迭代] 失败")
		return errors.New("删除迭代失败")
	}

	return nil
}

// DeleteIterationByProjectId /* 通过项目ID删除迭代
func (p *ProjectServer) DeleteIterationByProjectId(req *proto.ProjectIdInfo) error {
	if !CheckProjectExist(req.Id) {
		zap.S().Errorw("[DeleteIterationByProjectId] 查询 [项目] 失败")
		return errors.New("删除项目失败")
	}

	var iterations []model.Iteration
	result := global.DB.Model(&model.Iteration{}).Where("project_id = ?", req.Id).Delete(&iterations)
	if result.Error != nil {
		zap.S().Errorw("[DeleteIterationByProjectId] 删除 [迭代] 失败")
		return errors.New("删除项目失败")
	}
	return nil
}

// CheckIterationExist /* 检查迭代是否存在
func CheckIterationExist(iterationId uint64) bool {
	var iteration model.Iteration
	result := global.DB.First(&iteration, iterationId)
	if result.RowsAffected == 0 {
		return false
	}
	return true
}
